package com.chuangsi.common.utils;

import com.chuangsi.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

@Component
@Slf4j
public class FileUploadUtil {



    //以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
    private static final Logger logger = LoggerFactory.getLogger(FileUploadUtil.class);
    private static final Integer ZERO = 0;
    private static final Integer ONE_ZERO_TWO_FOUR = 1024;
    private static final Integer NINE_ZERO_ZERO = 900;
    private static final Integer THREE_TWO_SEVEN_FIVE = 3275;
    private static final Integer TWO_ZERO_FOUR_SEVEN = 2047;
    private static final Double ZERO_EIGHT_FIVE = 0.85;
    private static final Double ZERO_SIX = 0.6;
    private static final Double ZERO_FOUR_FOUR = 0.44;
    private static final Double ZERO_FOUR = 0.4;


    @Autowired
    private ConfigUtil configUtil;

    /**
     * 上传图片
     * @param multipartFile 文件流
     * @param catalog 文件存储目录
     * @return 文件名
     */
    public String upload(MultipartFile multipartFile, String catalog) {
        double fileSizeMB = multipartFile.getSize() / (1024.0 * 1024.0); // 转换为MB
        String fileName = multipartFile.getOriginalFilename();
        //获取文件格式
        int lastIndex = fileName.lastIndexOf('.');
        String suffix = "";
        if (lastIndex > 0) {
            suffix = fileName.substring(lastIndex);
        }
        //文件名(时间戳)+文件格式
        String name = System.currentTimeMillis() + suffix;
        //文件存储FILE
        String path = configUtil.getPath();
        File dest = new File(path + catalog + name);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        if(ImageUtil.PICSUFFIX.contains(suffix.toLowerCase().replace(".","")) && fileSizeMB > 1){
            //压缩图片
            imageCompression(multipartFile,dest.getPath());
        }else {
            try {
                // 存储文件
                multipartFile.transferTo(dest);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return name;
    }


    public static void imageCompression(MultipartFile file,String dest) {
        //获取文件输入流
        InputStream inputStream = null;
        try {
            inputStream = new ByteArrayInputStream(file.getBytes());
        }catch (Exception e){
            throw new ServiceException("数据错误,请联系管理员");
        }
        try {
            String getImageType = getImageType(file);
            // 把图片读入到内存中
            BufferedImage bufImg = ImageIO.read(inputStream);
            // 压缩代码,存储图片文件byte数组
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            //防止图片变红,这一步非常重要
            BufferedImage bufferedImage = new BufferedImage(bufImg.getWidth(), bufImg.getHeight(), BufferedImage.TYPE_INT_RGB);
            bufferedImage.createGraphics().drawImage(bufImg,0,0, Color.WHITE,null);
            //先转成jpg格式来压缩,然后在通过OSS来修改成源文件本来的后缀格式
            ImageIO.write(bufferedImage,getImageType,bos);
            //存图片
            byte2Img(bos.toByteArray(),dest);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
            }catch (Exception e){
                e.printStackTrace();
            }

        }
    }

    /**
     * 根据指定大小压缩图片
     * https://blog.csdn.net/wangwenzhe222/article/details/138603706
     * @param file  源图片
     * @return 压缩质量后的图片BASE64
     */
    public static void compressPicForScale(MultipartFile file,String dest) {
        //desFileSize 指定图片大小，单位kb
        long desFileSize = 300L;
        byte[] imageBytes = img2Byte(file);
        if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) {
            byte2Img(imageBytes,dest);
        }else {
            long srcSize = imageBytes.length;
            double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR);
            try {
                while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) {
                    ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                    Thumbnails.of(inputStream)
                            .scale(accuracy)
                            .outputQuality(accuracy)
                            .toOutputStream(outputStream);
                    imageBytes = outputStream.toByteArray();
                }
                byte2Img(imageBytes,dest);
                logger.info("图片原大小={}kb | 压缩后大小={}kb", srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR);
            } catch (Exception e) {
                logger.error("【图片压缩】msg=图片压缩失败!", e);
            }
        }
    }

    /**
     * 获取文件后缀不带.
     *
     * @param file 文件后缀名
     * @return
     */
    public static String getImageType(MultipartFile file) {
        String fileName = file.getName();
        int index = fileName.lastIndexOf(".");
        if (index != -1 && index < fileName.length() - 1) {
            return fileName.substring(index + 1);
        }
        return "jpg";
    }


    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < NINE_ZERO_ZERO) {
            accuracy = ZERO_EIGHT_FIVE;
        } else if (size < TWO_ZERO_FOUR_SEVEN) {
            accuracy = ZERO_SIX;
        } else if (size < THREE_TWO_SEVEN_FIVE) {
            accuracy = ZERO_FOUR_FOUR;
        } else {
            accuracy = ZERO_FOUR;
        }
        return accuracy;
    }

    /**
     * 图片转字节数组
     * @param file 上传文件
     * @return 字节数组
     */
    public static byte[] img2Byte(MultipartFile file){
        byte[] imageBytes = new byte[0];
        try {
            // 读取图片
            BufferedImage image = ImageIO.read(file.getInputStream());
            // 创建字节输出流
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            // 使用ImageIO将BufferedImage编码为byte[]
            ImageIO.write(image, "jpg", baos);
            // 转换为字节数组
            imageBytes = baos.toByteArray();
            // 关闭字节输出流
            baos.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return imageBytes;
    }

    /**
     * 字节转图片
     * @param imageBytes 字节
     * @param filePath 图片地址
     */
    public static void byte2Img(byte[] imageBytes,String filePath){
        // 将字节数组转换为BufferedImage
        try {
            BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageBytes));
            // 确保image不为null，即字节数组确实是一个图片的有效表示
            if (image != null) {
                // 将BufferedImage保存为文件
                File outputFile = new File(filePath);
                String substring = filePath.substring(filePath.lastIndexOf("." )+1);
                ImageIO.write(image,substring, outputFile);
            } else {
                System.out.println("字节数组不是有效的图片数据");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}
